package com.example.k8s.hello.boot.oss.service;

import com.example.k8s.hello.boot.oss.ObjectStat;
import com.example.k8s.hello.boot.oss.template.OssTemplate;
import com.example.k8s.hello.boot.oss.utils.ImgUtil;
import com.example.k8s.hello.common.exception.ApiExEnum;
import com.example.k8s.hello.common.exception.BizException;
import com.example.k8s.hello.common.utils.SnowflakeIdWorker;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;

/**
 * Oss服务
 */
@Slf4j
@RequiredArgsConstructor
public class OssService implements IOssService {

    private final OssTemplate ossTemplate;

    /**
     * 创建文件分组
     * @param bucket
     */
    @Override
    public void createBucket(String bucket) {
        ossTemplate.createBucket(bucket);
    }

    /**
     * 删除文件分组
     * @param bucket
     */
    @Override
    public void deleteBucket(String bucket) {
        ossTemplate.deleteBucket(bucket);
    }

    /**
     * 上传文件
     * @param file   待上传的文件
     * @param bucket 文件分组
     * @return 文件路径
     */
    @Override
    public String uploadFile(MultipartFile file, String bucket) {
        String fileName = file.getOriginalFilename();

        String newFileName = SnowflakeIdWorker.nextIdStr();

        if (fileName.lastIndexOf(".") < fileName.length() - 1) {
            newFileName = newFileName + fileName.substring(fileName.lastIndexOf("."));
        }

        try (InputStream is = file.getInputStream()) {
            ossTemplate.putObject(is, newFileName, bucket);

            return newFileName;
        } catch (Exception e) {
            throw new BizException(ApiExEnum.B0002.name(), "文件上传出错", e);
        }
    }

    /**
     * 上传Base64图片
     * @param base64Image Base64图片
     * @param bucket      图片分组
     * @return 文件路径
     */
    @Override
    public String uploadBase64Image(String base64Image, String bucket) {
        String fileName =  SnowflakeIdWorker.nextIdStr() + ".png";

        try (ByteArrayOutputStream out = ImgUtil.base64ToOutputStream(base64Image);
             InputStream in = new ByteArrayInputStream(out.toByteArray())){

            ossTemplate.putObject(in, fileName, bucket);

            return fileName;
        } catch (IOException e) {
            throw new BizException(ApiExEnum.B0002.name(), "上传Base64图片出错", e);
        }
    }

    /**
     * 删除文件
     * @param name   文件地址
     * @param bucket 文件分组
     */
    @Override
    public void deleteObject(String name, String bucket) {
        ossTemplate.deleteObject(name, bucket);
    }

    /**
     * 下载缩略图
     * @param name   图片地址
     * @param bucket 图片分组
     * @return 图片信息
     */
    @Override
    public void downloadThumbnail(String name, String bucket, int targetWidth, int targetHeight, HttpServletResponse response) {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
             InputStream in = ossTemplate.getObject(name, bucket)) {

            String format = getFormat(name);

            ImgUtil.resizeImage(in, out, format, targetWidth, targetHeight);

            try (ByteArrayInputStream resizeIn = new ByteArrayInputStream(out.toByteArray())) {
                doDownload(name, bucket, response, resizeIn);
            }
        } catch (IOException e) {
            throw new BizException(ApiExEnum.B0002.name(), "下载缩略图出错", e);
        }
    }

    /**
     * 编码Base64图片
     * @param name
     * @param bucket
     * @return
     */
    @Override
    public String encodeBase64Image(String name, String bucket) {
        BufferedImage bufferedImage = doGetImage(name, bucket);
        String base64 = ImgUtil.bufferedImageToBase64(bufferedImage);
        return base64;
    }

    /**
     * 下载水印图片
     * @param name
     * @param bucket
     * @return
     */
    @Override
    public void downloadWatermark(String name, String bucket, HttpServletResponse response){
        try (InputStream in = ossTemplate.getObject(name, bucket);
             ByteArrayOutputStream out = new ByteArrayOutputStream()) {

            String format = getFormat(name);

            ImgUtil.addTextWatermark(in, out, format);

            try (ByteArrayInputStream watermarkIn = new ByteArrayInputStream(out.toByteArray())) {
                doDownload(name, bucket, response, watermarkIn);
            }
        } catch (IOException e) {
            throw new BizException(ApiExEnum.B0002.name(), "下载水印图片出错", e);
        }
    }

    /**
     * 文件下载
     * @param name
     * @param bucket
     * @param response
     */
    @Override
    public void download(String name, String bucket, HttpServletResponse response){
        try (InputStream in = ossTemplate.getObject(name, bucket)) {
            doDownload(name, bucket, response, in);
        } catch (IOException e) {
            throw new BizException(ApiExEnum.B0002.name(), "文件下载出错", e);
        }
    }

    @Override
    public List<String> listBuckets() {
        return ossTemplate.listBuckets();
    }

    @Override
    public List<String> listObjects(String bucket){
        return ossTemplate.listObjects(bucket);
    }

    @Override
    public void deleteObjects(String bucket, List<String> objects){
        ossTemplate.deleteObjects(bucket, objects);
    }

    /**
     * 获取图片信息
     *
     * @param name   图片地址
     * @param bucket 图片分组
     * @return 图片信息
     */
    private BufferedImage doGetImage(String name, String bucket) {
        try (InputStream in = ossTemplate.getObject(name, bucket)) {
            return ImageIO.read(in);
        } catch (IOException e) {
            throw new BizException(ApiExEnum.B0002.name(), "获取图片信息出错", e);
        }
    }

    /**
     * 文件下载
     * @param name
     * @param bucket
     * @param response
     */
    private void doDownload(String name, String bucket, HttpServletResponse response, InputStream in){
        ObjectStat stat = ossTemplate.getObjectStat(name, bucket);
        response.setContentType(stat.getContentType());
        response.setCharacterEncoding("UTF-8");

        try {
            // 浏览器打开资源时会默认下载，当资源为图片时不合适，应当由前端控制
//            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(stat.getName(), "UTF-8"));

            response.setContentLength(in.available());
            IOUtils.copy(in, response.getOutputStream());
        } catch (UnsupportedEncodingException e) {
            throw new BizException(ApiExEnum.B0002.name(), "文件下载文件名url编码出错", e);
        }catch (IOException e) {
            throw new BizException(ApiExEnum.B0002.name(), "文件下载出错", e);
        }
    }

    private static String getFormat(String name) {
        String format = "png";
        if (name.lastIndexOf(".") < name.length() - 1) {
            format = name.substring(name.lastIndexOf(".") + 1);
        }
        return format;
    }

}
